//#define OFFLINE
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Xeml.Document;
using Xeml.Document.EnvironmentalOntology;
using Mpi.Common.Collections;
using Xeml.Document.Contracts;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Xeml.Document.CoreObjects;

namespace Xid.Controls.ParameterBrowserCtrls
{
    public partial class ParameterTreeCtrl : UserControl
    {
        public delegate void MessageEmittedEventHandler(object sender, MessageEventArgs e);
        public event MessageEmittedEventHandler MessageEmitted;
 
        public void StatusUpdate(string message)
        {
            if (MessageEmitted != null)
            {
                MessageEmitted(this, new MessageEventArgs(message, EventLogEntryType.Information));
            }
        } 

        public int FilterLevel
        {
            get { return this.comboBoxImportanceFilter.SelectedIndex; }
        }

        private int importanceLevel = 1;
        private Dictionary<string, ParamTreeNode> outSortedNodes = new Dictionary<string, ParamTreeNode>();

        private StoryBase story;
        private DocumentResources _resources;

        private bool _allowNavigation;


        public bool AllowNavigation
        {
            get { return _allowNavigation; }
            set { _allowNavigation = value; }
        }

        public StoryBase Story
        {
            get
            {
                return this.story;
            }
        }

        public ParamTreeNode SelectedNode
        {
            get { return (ParamTreeNode)treeView.SelectedNode; }

        }

        public ParameterTreeCtrl()
        {
            InitializeComponent();
            comboBoxImportanceFilter.SelectedIndexChanged += new EventHandler(comboBoxImportanceFilter_SelectedIndexChanged);
            comboBoxImportanceFilter.SelectedIndex = 0;
            contextMenuStrip.Opening += new CancelEventHandler(contextMenuStrip1_Opening);

            //openToolStripMenuItem.Click += new EventHandler(OnOpenParameter);
            expandAllToolStripMenuItem.Click += new EventHandler(OnExpandAllSubNodes);
            expandToolStripMenuItem.Click += new EventHandler(OnExpandNode);
            collapseAllToolStripMenuItem.Click += new EventHandler(OnCollapseAll);
            collapseToolStripMenuItem.Click += new EventHandler(OnCollapse);
            populateToolStripMenuItem.Click += new EventHandler(OnPopulateParameter);
            dropToolStripMenuItem.Click += new EventHandler(OnRemoveParameter);
            treeView.AfterSelect += new TreeViewEventHandler(treeView_AfterSelect);
        }

        void comboBoxImportanceFilter_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this._resources != null)
            {
                switch (comboBoxImportanceFilter.Text)
                {
                    case "All":
                        {
                            this.importanceLevel = 1;
                            break;
                        }
                    case "Important":
                        {
                            this.importanceLevel = 2;
                            break;
                        }
                    case "MostImportant":
                        {
                            this.importanceLevel = 3;
                            break;
                        }
                    default:
                        goto case "All";
                }
                foreach (OntologyHandlerResource ohr in this._resources.EnvironmentOntologyHandler)
                {
                    FilterOut(ohr);
                    SetLabels(ohr.NameSpaceAlias);
                }
            }
        }

        void OnPopulateParameter(object sender, EventArgs e)
        {
            PopulateVariable(this.SelectedNode);
        }

        void OnRemoveParameter(object sender, EventArgs e)
        {
            RemoveVariableFromCurrentNode();
        }

        private void RemoveVariableFromCurrentNode()
        {
            if (this.SelectedNode.Variable != null)
            {
                this.story.Variables.Remove(this.SelectedNode.Variable.TermId);
                this.SelectedNode.VariableSupervisor.RejectSupervison(this.SelectedNode.Variable);
                //this.SelectedNode.Variable = null;
                if (this.ParameterDePopulated != null)
                {
                    this.ParameterDePopulated(this, new EventArgs());
                }
            }
        }

        private void PopulateVariable(ParamTreeNode node)
        {
            IDynamicOntologyTerm ps = node.VariableSupervisor;// this.SelectedNode.VariableSupervisor;
            DynamicTerm variable = null;
            TimeSpan startTime = TimeSpan.Zero;
            variable = (DynamicTerm)ps.EmitDefaultObject(true); //lets get a default object 

            if (this.story is StorySplit) //in case of a derived story we have to adjust the start time of the Varaible
            {
                startTime = (story as StorySplit).TimePoint;
                foreach (DynamicValueBase vb in variable.Values)
                {
                    vb.Time = startTime;
                }
            }

            this.story.Variables.Add(variable); //add the variable to the story
            this.SelectedNode.Variable = variable; //let the TreenNode know that he is initialized know
            if (this.ParameterPopulated != null)
            {
                this.ParameterPopulated(this, new EventArgs());
            }

            //p.NameSpaceAlias = this.SelectedNode.NsAlias;
            //p.Name = this.SelectedNode.ParameterSpec.Name;
            //p.GroupPath = this.SelectedNode.ParameterSpec.GroupPath;
            //p.NameSpace = DocumentHelper.ResolveAliasToNameSpace(this.envOntologyHandlers, p.NameSpaceAlias);
            //foreach (ParameterContextSpec pcs in this.SelectedNode.ParameterSpec.ContextCollection)
            //{
            //    if (pcs.DefaultCycle != null)
            //    {
            //        Cycle c = new Cycle();
            //        c.Time = startTime;
            //        c.Context = pcs.Name;
            //        if (pcs.UnitSet.DefaultUnit != null)
            //            c.Unit = pcs.UnitSet.DefaultUnit.Symbol;
            //        foreach (KeyValuePair<TimeSpan, string> kvp in pcs.DefaultCycle)
            //        {
            //            c.Values.Add(new Value(kvp.Key, kvp.Value));
            //        }
            //        p.Values.Add(c);
            //    }
            //    if (pcs.DefaultValue != null && pcs.DefaultCycle == null)
            //    {
            //        Value v = new Value(startTime, pcs.DefaultValue);
            //        v.Context = pcs.Name;
            //        if (pcs.UnitSet.DefaultUnit != null)
            //            v.Unit = pcs.UnitSet.DefaultUnit.Symbol;
            //        p.Values.Add(v);
            //    }
            //}
            //this.Parameter = p;
        }

        #region ContextMenuEvents
        void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            if (this.story == null)
            {
                selectAStoryFirstToolStripMenuItem.Visible = true;
                //openToolStripMenuItem.Visible = false;
                dropToolStripMenuItem.Visible = false;
                populateToolStripMenuItem.Visible = false;
                // toolStripSeparator1.Visible = false;
                return;
            }
            if (treeView.SelectedNode != null)
            {
                selectAStoryFirstToolStripMenuItem.Visible = false;
                if (this.SelectedNode.Variable != null)
                {
                    //openToolStripMenuItem.Visible = true && _allowNavigation;
                    dropToolStripMenuItem.Visible = true;
                    populateToolStripMenuItem.Visible = true;
                    toolStripSeparator1.Visible = true;

                    //openToolStripMenuItem.Font = new Font(openToolStripMenuItem.Font, FontStyle.Bold);
                    populateToolStripMenuItem.Font = new Font(populateToolStripMenuItem.Font, FontStyle.Regular);
                    //openToolStripMenuItem.Enabled = true && _allowNavigation;
                    dropToolStripMenuItem.Enabled = true;
                    populateToolStripMenuItem.Enabled = false;
                }
                else
                {
                    //openToolStripMenuItem.Visible = true && _allowNavigation;
                    dropToolStripMenuItem.Visible = true;
                    populateToolStripMenuItem.Visible = true;
                    toolStripSeparator1.Visible = true;
                    // openToolStripMenuItem.Font = new Font(openToolStripMenuItem.Font, FontStyle.Regular);
                    populateToolStripMenuItem.Font = new Font(populateToolStripMenuItem.Font, FontStyle.Bold);
                    //openToolStripMenuItem.Enabled = false && _allowNavigation;
                    dropToolStripMenuItem.Enabled = false;
                    populateToolStripMenuItem.Enabled = true;
                }
                if (this.SelectedNode.VariableSupervisor == null)
                {
                    //openToolStripMenuItem.Visible = false;
                    dropToolStripMenuItem.Visible = false;
                    populateToolStripMenuItem.Visible = false;
                    toolStripSeparator1.Visible = false;
                    infoToolStripMenuItem.Visible = false;
                    toolStripSeparator2.Visible = false;
                }
                else
                {
                    toolStripSeparator2.Visible = true;
                    infoToolStripMenuItem.Visible = true;
                }
            }
            else
            {

            }
        }

        void OnCollapse(object sender, EventArgs e)
        {
            if (this.SelectedNode != null)
                this.SelectedNode.Collapse(true);
        }

        void OnCollapseAll(object sender, EventArgs e)
        {
            if (this.SelectedNode != null)
                this.SelectedNode.Collapse(false);
        }

        void OnExpandNode(object sender, EventArgs e)
        {
            if (this.SelectedNode != null)
                this.SelectedNode.Expand();
        }

        void OnExpandAllSubNodes(object sender, EventArgs e)
        {
            if (this.SelectedNode != null)
                this.SelectedNode.ExpandAll();
        }

        //void OnOpenParameter(object sender, EventArgs e)
        //{
        //    OnParmaterNavigationRequested(this.SelectedNode.Parameter);
        //}
        #endregion

        void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if ((e.Node as ParamTreeNode).VariableSupervisor != null)
            {
                SelectedVariableNode = e.Node as ParamTreeNode;

                if (SelectedParamTreeNodeChanged != null)
                {
                    SelectedParamTreeNodeChanged(this, new EventArgs());
                }
            }
        }

        public ParamTreeNode SelectedVariableNode { get; private set; }

        public void Setup(DocumentResources res, int filterLevel)
        {
            this.outSortedNodes.Clear();
            this.treeView.Nodes.Clear();

            //unsubscribe from current document resources
            if (_resources != null)
            {
                _resources.HandlerResourceAdded -= new EventHandler<ItemEventArgs<OntologyHandlerResource>>(envOntologyHandlers_ItemAdded);
                _resources.HandlerResourceRemoved -= new EventHandler<ItemEventArgs<OntologyHandlerResource>>(envOntologyHandlers_ItemRemoved);
                _resources.HandlerResourcesCleared -= new EventHandler(envOntologyHandlers_Cleared);
            }

            _resources = res;

            //attempt solve OutOfMemoryException when setting Label in ParamTreeNode set SetLabel() method
            //found at http://thedailyreviewer.com/dotnet/view/gdi-leaks-112108591
            //succefully tested on dev machine by bitdisaster
            //GC.Collect() needs to be called twice 
            GC.Collect();
            GC.Collect();

            //subscribe to current document resources
            if (_resources != null)
            {
                _resources.HandlerResourceAdded += new EventHandler<ItemEventArgs<OntologyHandlerResource>>(envOntologyHandlers_ItemAdded);
                _resources.HandlerResourceRemoved += new EventHandler<ItemEventArgs<OntologyHandlerResource>>(envOntologyHandlers_ItemRemoved);
                _resources.HandlerResourcesCleared += new EventHandler(envOntologyHandlers_Cleared);

                SetupParams(filterLevel);
            }
        }

        private void SetupParams(int filterLevel)
        {
            this.treeView.SuspendLayout();

            Parallel.ForEach(_resources.EnvironmentOntologyHandler, ohr =>
                {
                    ohr.LoadOntology();
                });

            foreach (OntologyHandlerResource ohr in _resources.EnvironmentOntologyHandler.Where(x => x.ComponentState == ComponentLoadState.Loaded).OrderByDescending(x => x.NameSpaceAlias))
            {
                PopulateOntology(ohr, filterLevel);
            }

            foreach (TreeNode tn in this.treeView.Nodes)
            {
                tn.Expand();
            }

            this.treeView.ResumeLayout();
        }

        public void SetupStory(StoryBase st, int filterLevel)
        {

            this.comboBoxImportanceFilter.SelectedIndex = filterLevel;
            if (this.story != null)
            {
                this.story.Variables.ItemAdded -= new EventHandler<ItemEventArgs<Term>>(OnParameterAdded);
                this.story.Variables.ItemRemoved -= new EventHandler<ItemEventArgs<Term>>(OnParameterRemoved);
                this.story.Variables.Cleared -= new EventHandler(OnParameterCleared);
            }
            this.story = st;

            treeView.SuspendLayout();
            foreach (ParamTreeNode ptn in treeView.Nodes)
            {
                ClearAllParameter(ptn);
            }
            if (st != null)
            {
                this.story.Variables.ItemAdded += new EventHandler<ItemEventArgs<Term>>(OnParameterAdded);
                this.story.Variables.ItemRemoved += new EventHandler<ItemEventArgs<Term>>(OnParameterRemoved);
                this.story.Variables.Cleared += new EventHandler(OnParameterCleared);
                foreach (DynamicTerm p in st.Variables)
                {
                    AddParameter(p);
                }
            }

            treeView.ResumeLayout();
            // SetLabels();
        }

        void OnParameterCleared(object sender, EventArgs e)
        {
            foreach (ParamTreeNode ptn in treeView.Nodes)
            {
                ClearAllParameter(ptn);
            }
        }

        void OnParameterRemoved(object sender, ItemEventArgs<Term> e)
        {
            RemoveVariable(e.Item);
        }

        private void AddParameter(Term p)
        {
            ParamTreeNode ptn = FindNode(treeView.Nodes, p.NameSpaceAlias + ":" + p.TermId);

            if (ptn != null)
            {
                ptn.Variable = (DynamicTerm)p;
                ptn.VariableSupervisor.Supervise(p);
                ptn.VariableSupervisor.PushSupervisedProperties();
            }
        }

        private void RemoveVariable(Term variable)
        {
            ParamTreeNode ptn = FindNode(treeView.Nodes, variable.NameSpaceAlias + ":" + variable.TermId);

            if (ptn != null)
            {

                ptn.Variable = null; //remove the variable from the TreeViewNode
            }
        }

        void OnParameterAdded(object sender, ItemEventArgs<Term> e)
        {
            AddParameter(e.Item);
        }


        /// <summary>
        /// Removes all Parameter.
        /// </summary>
        /// <param name="ptn">The start node.</param>
        private void ClearAllParameter(ParamTreeNode ptn)
        {
            ptn.Variable = null;
            foreach (ParamTreeNode x in ptn.Nodes)
            {
                ClearAllParameter(x);
            }
        }

        private ParamTreeNode FindNode(TreeNodeCollection treeNodeCollection, string key)
        {
            TreeNode[] tns = treeNodeCollection.Find(key, true);
            if (tns.Length > 0)
                return (ParamTreeNode)tns[0];
            else
                return null;
            //if (treeNodeCollection.ContainsKey(key))
            //    return (ParamTreeNode)treeNodeCollection[key];
            //else
            //{
            //    ParamTreeNode ret = null;
            //    foreach (TreeNode tn in treeNodeCollection)
            //    {
            //        ret = FindNode(tn.Nodes, key);
            //        if (ret != null)
            //            return ret;
            //    }
            //    return ret;
            //}
        }

        private void PopulateOntology(OntologyHandlerResource ohr, int filterLevel)
        {
            Dictionary<IDynamicOntologyTerm, ParamTreeNode> containerDict = new Dictionary<IDynamicOntologyTerm, ParamTreeNode>();

            IDynamicOntologyHandler eoh = ohr.Handler as IDynamicOntologyHandler;
            IHierarchicalView hv = ohr.Handler as IHierarchicalView;
            if (hv != null)
            {
                foreach (IDynamicOntologyTerm s in eoh.Terms)
                {
                    //IVariableSupervisor ps = (IVariableSupervisor)s;

                    containerDict.Add(s, GetFolderNode(hv.FindNode(s), ohr.NameSpaceAlias, ohr.Handler.NameSpace));
                }

                foreach (KeyValuePair<IDynamicOntologyTerm, ParamTreeNode> kvp in containerDict)
                {
                    ParamTreeNode tn2 = new ParamTreeNode();
                    tn2.Name = kvp.Key.Prototype.NameSpaceAlias + ":" + kvp.Key.TermId;
                    tn2.DisplayName = kvp.Key.Prototype.Name;
                    tn2.NsAlias = kvp.Key.Prototype.NameSpaceAlias;
                    kvp.Value.Add(tn2);
                    tn2.VariableSupervisor = kvp.Key;

                }
                SetLabels(ohr.NameSpaceAlias);

                comboBoxImportanceFilter.SelectedIndex = filterLevel;
            }
        }

        private void FilterOut(OntologyHandlerResource ohr)
        {
            ParamTreeNode root = (ParamTreeNode)treeView.Nodes[ohr.NameSpaceAlias];
            IDynamicOntologyHandler eoh = ohr.Handler as IDynamicOntologyHandler;
            //TODO:Filter Nodes
            //foreach (IDynamicOntologyTerm s in eoh.Terms)
            //{
            //    IVariableSupervisor pspec = (IVariableSupervisor)s;
            //    if (pspec.RecommendationLevel < this.importanceLevel)
            //    {
            //        ParamTreeNode tn = FindNode(root.Nodes, s.Prototype.NameSpaceAlias + ":" + s.TermId);
            //        if (tn != null)
            //        {
            //            FilterOutNode(tn, root);
            //        }
            //    }
            //    else
            //    {

            //        FilterInNode(s.Prototype.NameSpaceAlias + ":" + pspec.TermId, root);
            //    }

            //}
        }

        private void FilterInNode(string specName, ParamTreeNode root)
        {
            if (outSortedNodes.ContainsKey(specName))
            {
                ParamTreeNode ptn = outSortedNodes[specName];
                ParamTreeNode parent = FindNode(root.Nodes, ptn.ParentKey);
                if (parent != null)
                {
                    parent.Add(ptn);
                    outSortedNodes.Remove(specName);
                }
                else
                {
                    FilterInNode(ptn.ParentKey, root);
                    parent = FindNode(root.Nodes, ptn.ParentKey);
                    parent.Add(ptn);
                    outSortedNodes.Remove(specName);
                }
            }
        }

        private void FilterOutNode(ParamTreeNode tn, ParamTreeNode root)
        {
            ParamTreeNode parent = (ParamTreeNode)tn.Parent;
            parent.Remove(tn);
            this.outSortedNodes.Add(tn.Name, tn);
            if (parent != root && parent.Nodes.Count == 0)
                FilterOutNode(parent, root);
        }

        private void SetLabels(string rootNodeId)
        {
            TreeNode tn = this.treeView.Nodes[rootNodeId];
            if (tn != null)
            {
                int used = 0;
                SetCountToLabel(tn as ParamTreeNode, ref used);
            }
            //foreach (ParamTreeNode tn in treeView.Nodes)
            //{
            //    int used = 0;
            //    SetCountToLabel(tn, ref used);
            //}
        }

        private int SetCountToLabel(ParamTreeNode tn, ref int used)
        {
            if (tn.VariableSupervisor != null)
            {
                //we found a leaf with OntologyTerm on it
                if (tn.Variable != null) //the leaf has a variable assoxiated
                    used++;

                return 0;
            }
            else
            {
                int termCount = 0;
                foreach (ParamTreeNode subTn in tn.Nodes)
                {
                    //get the subcount recursive
                    termCount += SetCountToLabel(subTn, ref used);
                }

                foreach (ParamTreeNode subTn in tn.Nodes)
                {
                    if (subTn.VariableSupervisor != null) //count the OntologyTerms not the folder
                        termCount++;
                }

                tn.AllSpecs = termCount;// tn.DisplayName + "(" + used + "/" + x + ")";
                return termCount;
            }
        }

        private ParamTreeNode GetFolderNode(TermNode ps, string nsAlias, string ns)
        {
            ParamTreeNode lastNode = null;
            List<string> treeLevel = new List<string>();
            treeLevel.Add(nsAlias);

            treeLevel.AddRange(ps.Path.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));

            for (int i = 0; i < treeLevel.Count - 1; i++) //just go to the parent folder of the Term not to the term itself
            {
                string groupPath = string.Join(".", treeLevel.Take(i + 1));

                if (lastNode == null)
                {
                    if (treeView.Nodes.ContainsKey(groupPath))
                    {
                        lastNode = (ParamTreeNode)treeView.Nodes[groupPath];
                    }
                    else
                    {
                        lastNode = new ParamTreeNode();
                        lastNode.Name = groupPath;
                        lastNode.DisplayName = treeLevel[i];

                        treeView.Nodes.Add(lastNode);
                        //treeView.Invoke(new MethodInvoker(delegate { treeView.Nodes.Add(lastNode); }));

                        //lastNode = (ParamTreeNode)treeView.Nodes[s];
                        if (lastNode.Level == 0)
                        {
                            lastNode.ImageIndex = 2;
                            lastNode.SelectedImageIndex = 2;
                            lastNode.ToolTipText = ns;
                        }
                        else
                        {
                            lastNode.SelectedImageIndex = 0;
                        }
                        lastNode.NodeFont = new Font("Segoe UI", 10f);
                    }
                }
                else
                {
                    if (lastNode.Nodes.ContainsKey(groupPath))
                    {
                        lastNode = (ParamTreeNode)lastNode.Nodes[groupPath];
                    }
                    else
                    {
                        ParamTreeNode tn = new ParamTreeNode();
                        tn.Name = groupPath;
                        tn.DisplayName = treeLevel[i];
                        //treeView.Nodes.Add(lastNode);
                        lastNode.Add(tn);

                        lastNode = tn;
                        if (lastNode.Level == 0)
                        {
                            lastNode.ImageIndex = 2;
                            lastNode.SelectedImageIndex = 2;
                            lastNode.ToolTipText = ns;
                        }
                        else
                        {
                            lastNode.SelectedImageIndex = 0;
                        }
                        lastNode.NodeFont = new Font("Segoe UI", 10f);
                    }
                }
            }
            return lastNode;
        }

        void envOntologyHandlers_Cleared(object sender, EventArgs e)
        {
            treeView.SuspendLayout();
            outSortedNodes.Clear();
            treeView.Nodes.Clear();
            treeView.ResumeLayout();
        }

        void envOntologyHandlers_ItemRemoved(object sender, ItemEventArgs<OntologyHandlerResource> e)
        {
            if (e.Item.ComponentState == ComponentLoadState.Loaded && e.Item.Handler.OntologyType == OntologyType.Environment)
            {
                treeView.SuspendLayout();
                this.treeView.Nodes.RemoveByKey(e.Item.NameSpaceAlias);
                treeView.ResumeLayout();
            }
        }

        void envOntologyHandlers_ItemAdded(object sender, ItemEventArgs<OntologyHandlerResource> e)
        {
            if (e.Item.ComponentState == ComponentLoadState.Loaded &&
                e.Item.Handler.OntologyType == OntologyType.Environment)
            {
                e.Item.LoadOntology();

                treeView.SuspendLayout();
                PopulateOntology(e.Item, 2);
                TreeNode current = this.treeView.Nodes[e.Item.NameSpaceAlias];
                if (current != null)
                {
                    current.Expand();
                }
                FilterOut(e.Item);
                SetLabels(e.Item.NameSpaceAlias);
                treeView.ResumeLayout();
            }
        }

        public void SelectFirst()
        {

        }

        public void SelectById(string fqName)
        {
            TreeNode[] ptn = treeView.Nodes.Find(fqName, true);
            this.treeView.SelectedNode = null;
            this.treeView.SelectedNode = ptn[0];
            this.treeView.SelectedNode.EnsureVisible();
            //if (this.treeView.SelectedNode.ParameterSpec != null && SelectedParamTreeNodeChanged != null)
            //    SelectedParamTreeNodeChanged(this, new EventArgs());

        }



        public event EventHandler SelectedParamTreeNodeChanged;
        public event EventHandler ParameterPopulated;
        public event EventHandler ParameterDePopulated;
        //public event EventHandler<ParameterNavEventArgs> ParmaterNavigationRequested;
        //private void OnParmaterNavigationRequested(Parameter p)
        //{
        //    if (ParmaterNavigationRequested != null && p != null)
        //    {
        //        ParmaterNavigationRequested(this, new ParameterNavEventArgs(p.TermId));
        //    }
        //}

        private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
                this.treeView.SelectedNode = e.Node;
        }

        private void treeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if ((e.Node as ParamTreeNode).VariableSupervisor != null && this.story != null)
            {
                if ((e.Node as ParamTreeNode).Variable == null)
                {
                    PopulateVariable(e.Node as ParamTreeNode);
                }

                //if (_allowNavigation)
                //    OnOpenParameter(sender, new EventArgs());
                //else
                //{
                //    OnPopulateParameter(sender, new EventArgs());
                //}
            }
        }

        private void infoToolStripMenuItem_Click(object sender, EventArgs e)
        {
#if OFFLINE
            if (MessageBox.Show("This function will contact the webserver  www.codeplex.com/XeO. Do you want proceed?", "Online contact", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
                == DialogResult.No)
                return;
#endif

            //if (this.SelectedNode != null && this.SelectedNode.ParameterSupervisor!= null && this.SelectedNode.ParameterSupervisor.CommunityUrl != null)
            //{
            //    //TODO:Online support 
            //  //  Process.Start(this.SelectedNode.ParameterSupervisor.CommunityUrl.AbsoluteUri);
            //}
            //else if(this.SelectedNode != null && this.SelectedNode.ParameterSupervisor!= null)
            //Process.Start(@"http://www.codeplex.com/XeO/Wiki/View.aspx?title=" + this.SelectedNode.VariableSupervisor.TermId);
            Process.Start(string.Concat(@"http://purl.bioontology.org/ontology/XeO/", this.SelectedNode.VariableSupervisor.TermId));
        }
    }

    public class ParamTreeNode : TreeNode
    {
        private DynamicTerm _term;
        private IDynamicOntologyTerm _ontologyTerm;
        private bool isRoot;
        private string displayName;
        private string nsAlias;
        private string parentKey;

        public string ParentKey
        {
            get { return parentKey; }
            set { parentKey = value; }
        }



        public string NsAlias
        {
            get { return nsAlias; }
            set { nsAlias = value; }
        }

        public string DisplayName
        {
            get { return displayName; }
            set { displayName = value; this.Text = value; }
        }


        public bool IsRoot
        {
            get { return isRoot; }
            set { isRoot = value; SetupIsRoot(); }
        }

        private void SetupIsRoot()
        {
            if (IsRoot)
            {
                this.ImageIndex = 2;
                this.SelectedImageIndex = 2;
                // this.ToolTipText = ns;

            }
        }


        public IDynamicOntologyTerm VariableSupervisor
        {
            get { return _ontologyTerm; }
            set
            {
                _ontologyTerm = value;
                SetupParamSpec();
                if (_ontologyTerm != null)
                {
                    if (ParamSpecPopulated != null)
                    {
                        ParamSpecPopulated(this, new EventArgs());
                    }
                }
            }
        }


        public ParamTreeNode()
            : base()
        {


        }


        private void SetupParamSpec()
        {
            if (this._ontologyTerm != null)
            {
                this.ImageIndex = 1;
                this.SelectedImageIndex = 1;

                //check whether the 
                if (_ontologyTerm.Attributes.Exists(x => x.Name == "RecommendationLevel"))
                {
                    int recLevel;
                    TermAttribute ta = _ontologyTerm.Attributes.Find("RecommendationLevel");
                    if (int.TryParse(ta.Value, out recLevel))
                    {
                        this.NodeFont = new Font("Segoe UI", 8.25f + (float)(Math.Log(recLevel, 1.2)));
                    }
                }
                this.ForeColor = Color.Silver;
                this.ToolTipText = _ontologyTerm.Definition;
                //this.Tag = ps;
            }
            else
            {
                this.ImageIndex = 0;
                this.SelectedImageIndex = 0;
                this.NodeFont = new Font("Segoe UI", 10f);
                this.ForeColor = Color.Black;
                this.ToolTipText = "";
                //tn.Tag = ps;
            }
        }


        public DynamicTerm Variable
        {
            get { return _term; }
            set
            {
                if (_term != value)
                {
                    _term = value;
                    SetupVariable();
                    if (_term != null)
                    {
                        if (ParameterPopulated != null)
                        {
                            ParameterPopulated(this, new EventArgs());
                        }
                    }
                    else
                    {
                        if (ParameterDePopulated != null)
                        {
                            ParameterDePopulated(this, new EventArgs());
                        }
                    }
                }
            }
        }

        private void SetupVariable()
        {
            if (this._term != null)
            {
                this.ForeColor = Color.RoyalBlue;
                this.SelectedImageIndex = 3;
                this.ImageIndex = 3;
            }
            else
            {
                this.ForeColor = Color.Silver;
                this.SelectedImageIndex = 1;
                this.ImageIndex = 1;
            }
        }


        private Font _boldFont;
        private Font _regularFont;

        private void SetLabel()
        {
            //     if (_boldFont == null)
            _boldFont = new Font(this.NodeFont, FontStyle.Bold);
            // if (_regularFont == null)
            _regularFont = new Font(this.NodeFont, FontStyle.Regular);

            if (poulatedPrams > 0)
                this.NodeFont = _boldFont;
            else
                this.NodeFont = _regularFont;
            this.Text = string.Concat(this.displayName, "(", poulatedPrams, "/", allSpecs, ")");
        }


        public void Add(ParamTreeNode ptn)
        {
            this.Nodes.Add(ptn);
            ptn.ParentKey = this.Name;
            //ptn.ParamSpecPopulated += new EventHandler(ptn_Specpopulated);
            ptn.ParameterPopulated += new EventHandler(ptn_ParameterPopulated);
            ptn.ParameterDePopulated += new EventHandler(ptn_ParameterDePopulated);


            //SetLabel();
        }


        private int poulatedPrams = 0;
        void ptn_ParameterDePopulated(object sender, EventArgs e)
        {
            poulatedPrams--;
            SetLabel();
            if (ParameterDePopulated != null)
            {
                ParameterDePopulated(sender, e);
            }
        }

        void ptn_ParameterPopulated(object sender, EventArgs e)
        {
            poulatedPrams++;
            SetLabel();
            if (ParameterPopulated != null)
            {
                ParameterPopulated(sender, e);
            }
        }

        private int allSpecs = 0;

        public int AllSpecs
        {
            get { return allSpecs; }
            set
            {
                if (value != allSpecs)
                {
                    allSpecs = value;
                    SetLabel();
                }
            }
        }
        void ptn_Specpopulated(object sender, EventArgs e)
        {
            allSpecs++;
            SetLabel();
            if (ParamSpecPopulated != null)
            {
                ParamSpecPopulated(sender, e);
            }
        }


        public event EventHandler ParamSpecPopulated;
        internal event EventHandler ParameterPopulated;
        internal event EventHandler ParameterDePopulated;


        internal void Remove(ParamTreeNode tn)
        {
            this.Nodes.Remove(tn);

            //ptn.ParamSpecPopulated += new EventHandler(ptn_Specpopulated);
            tn.ParameterPopulated -= new EventHandler(ptn_ParameterPopulated);
            tn.ParameterDePopulated -= new EventHandler(ptn_ParameterDePopulated);
        }
    }

    public class ParameterNavEventArgs : EventArgs
    {
        public string Target { get; private set; }

        public ParameterNavEventArgs(string target)
        {
            this.Target = target;
        }
    }
}
